package com.kyin.satoken.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**
 * @author yin.kai
 * @ClassName JwtUtil
 * @description: JWT工具类，提供生成token、验证token和解析token的功能
 * @date 2025/9/23 16:39
 * @version: 1.0
 */
public class JwtUtil {

    // 密钥，实际应用中应使用更复杂的密钥并妥善保管
    private static final String SECRET_KEY = "5be967df64d8cc53a47494533129b909362709e05b6f0723f546d78acc183b58";

    // token过期时间，这里设置为1小时（3600000毫秒）
    private static final long EXPIRATION_TIME = 1 * 60 * 60 * 1000;

    /**
     * 生成JWT token
     * @param subject 主题，通常是用户名或用户ID
     * @return 生成的token字符串
     */
    public static String generateToken(String subject) {
        return generateToken(new HashMap<>(), subject);
    }

    /**
     * 生成带有自定义声明的JWT token
     * @param claims 自定义声明
     * @param subject 主题，通常是用户名或用户ID
     * @return 生成的token字符串
     */
    public static String generateToken(Map<String, Object> claims, String subject) {
        // 生成当前时间和过期时间
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + EXPIRATION_TIME);

        // 生成密钥
        SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());

        // 构建并返回JWT token
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(now)
                .setExpiration(expirationDate)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    /**
     * 验证token是否有效
     * @param token 要验证的token
     * @param subject 预期的主题（用户名或用户ID）
     * @return 如果token有效且主题匹配则返回true，否则返回false
     */
    public static boolean validateToken(String token, String subject) {
        try {
            String tokenSubject = extractSubject(token);
            // 验证主题是否匹配且token未过期
            return (tokenSubject.equals(subject) && !isTokenExpired(token));
        } catch (Exception e) {
            // 任何异常都表示token无效
            return false;
        }
    }

    /**
     * 从token中提取主题
     * @param token JWT token
     * @return 主题字符串
     */
    public static String extractSubject(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    /**
     * 从token中提取过期时间
     * @param token JWT token
     * @return 过期时间Date对象
     */
    public static Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    /**
     * 从token中提取指定的声明
     * @param token JWT token
     * @param claimsResolver 声明解析器
     * @param <T> 声明类型
     * @return 声明值
     */
    public static <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 从token中提取所有声明
     * @param token JWT token
     * @return 包含所有声明的Claims对象
     */
    public static Claims extractAllClaims(String token) {
        SecretKey key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 检查token是否已过期
     * @param token JWT token
     * @return 如果已过期返回true，否则返回false
     */
    private static boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }
}

